package com.zyy.seckill.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zyy.seckill.entity.User;
import com.zyy.seckill.exception.GlobalException;
import com.zyy.seckill.mapper.UserMapper;
import com.zyy.seckill.service.IUserService;
import com.zyy.seckill.utils.CookieUtil;
import com.zyy.seckill.utils.MD5Util;
import com.zyy.seckill.utils.UUIDUtil;
import com.zyy.seckill.vo.LoginVo;
import com.zyy.seckill.vo.RespBean;
import com.zyy.seckill.vo.RespEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author zyy
 * @since 2021-10-03
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 登录校验
     *
     * @param loginVo
     * @param request
     * @param response
     * @return
     */
    @Override
    public RespBean doLongin(LoginVo loginVo, HttpServletRequest request, HttpServletResponse response) {
        String mobile = loginVo.getMobile();
        String password = loginVo.getPassword();
//        if (!StringUtils.hasLength(mobile) || !StringUtils.hasLength(password) ){
//            return  RespBean.error(RespEnum.LOGIN_ERROR);
//        }
//        if (!ValidatorUtil.isMobile(mobile)){
//            return RespBean.error(RespEnum.MOBILE_ERROR);
//        }
        // 根据手机号获取用户信息
        User user = userMapper.selectById(mobile);
        if (null == user) {
            throw new GlobalException(RespEnum.LOGIN_ERROR);
        }
        if (!MD5Util.formPassToDBPass(password, user.getSlat()).equals(user.getPassword())) {// 判断表单取出的数据第二次加密后和数据库进行比较是否相同
            throw new GlobalException(RespEnum.LOGIN_ERROR);
        }
        // 生成cookie
        String ticket = UUIDUtil.uuid();  //生成 sessionID

//        request.getSession().setAttribute(ticket,user); // 以sessionID 对应 登录的user

        redisTemplate.opsForValue()
                .set("user:" + ticket, user);//操作string类型的方法

        CookieUtil.setCookie(request, response, "userTicket", ticket); // 封装cookie ; 把session的id作为cookie的value放回作用域中

        return RespBean.success(ticket);
    }

    /**
     * 根据cookie的value取出redis中存储的对象的值
     *
     * @param userTicket
     * @return user
     */
    @Override
    public User getUserByCookie(String userTicket,
                                HttpServletRequest request, HttpServletResponse response) {
        if (!StringUtils.hasLength(userTicket)) {
            return null;
        }
        User user = (User) redisTemplate.opsForValue().get("user:" + userTicket);// 获取redis存储的对象
        if (user != null) { //为了防止cookie误删除 ,再次放回cookie中
            CookieUtil.setCookie(request, response, "userTicket", userTicket);
        }
        return user;
    }

    /**
     * 用户密码更新
     *
     * @param userTicket 从cookie中获取的redis中存储的对象的键
     * @param password
     * @param request
     * @param response
     * @return
     */
    @Override
    public RespBean updatePassWord(String userTicket, String password,
                                   HttpServletRequest request, HttpServletResponse response) {
        User user = getUserByCookie(userTicket, request, response);
        if (user == null) {
            throw new GlobalException(RespEnum.MOBILE_NOT_EXIST);
        }
        user.setPassword(MD5Util.inputPassToDBPass(password, user.getSlat()));
        int i = userMapper.updateById(user);
        if (1 == i) { //更新成功就更新redis
            redisTemplate.delete("user:"+userTicket);
            return RespBean.success(userTicket);
        }
        return RespBean.error(RespEnum.PASSWORD_UPDATE_FAIL);
    }
}

/**
 * 使用redis 解决分布式session的俩种方式
 * 1.使用 spring自带的 spring-session -data -redis依赖,
 * 它可以直接把session域中的数据全部以二进制的方式封装存储在redis中
 * <p>
 * 2.自定义configuration 设置 对象和redis存储结构的序列化,
 * 然后直接把登陆成功的用户存储在redis中 ,key为创建生成的cookie的value,
 * 该过程不需要session
 */
